/*
 * BasePropertyEditorJPanel.java
 *
 * Created on 30 mei 2007, 9:14
 */

package net.jwtools.tmt.ui.propertyeditor;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JTextField;
import javax.swing.UIManager;

import net.jwtools.tmt.service.Filter;
import net.jwtools.tmt.service.NamedObject;
import net.jwtools.tmt.ui.event.SearchEvent;
import net.jwtools.tmt.ui.event.SearchEventListener;
import net.jwtools.tmt.ui.renderer.ComboBoxToolTipRenderer;
import net.jwtools.tmt.util.DeepCopy;
import net.jwtools.tmt.util.ExtendedControl;

import org.springframework.context.MessageSource;

import com.l2fprod.common.propertysheet.Property;
import com.l2fprod.common.propertysheet.PropertySheet;
import com.l2fprod.common.propertysheet.PropertySheetPanel;

/**
 * 
 * @author naftali
 */
public abstract class BasePropertyEditorJPanel extends javax.swing.JPanel {
	protected ResourceBundle bundle = ResourceBundle.getBundle("net/jwtools/tmt/ui/messages", new ExtendedControl());
	
	private Map objectMap = new HashMap();

	private NamedObject defaultObject;

	private NamedObject currentObject;

	private Property lastChangedProperty;

	private PropertyChangeListener propertyChangeListener;

	protected List searchEventListeners = new ArrayList();

	/**
	 * Creates new form BasePropertyEditorJPanel
	 */
	public BasePropertyEditorJPanel() {
		initComponents();
		getPropertySheet().setDescriptionVisible(true);
		getPropertySheet().setMode(PropertySheet.VIEW_AS_CATEGORIES);
		getPropertySheet().setToolBarVisible(false);
		getPropertySheet().setRendererFactory(new BasePropertyRendererFactory());
		getPropertySheet().setEditorFactory(new BasePropertyEditorFactory());
		jComboBox.setRenderer(new ComboBoxToolTipRenderer());
		jComboBox.setEditable(true);
		initListeners();
	}

	private void initListeners() {
		propertyChangeListener = new PropertyChangeListener() {
			public void propertyChange(PropertyChangeEvent evt) {
				Property prop = (Property) evt.getSource();
				try {
					System.out.println("change " + prop);
					editorChanged();
				} catch (RuntimeException e) {
					// handle PropertyVetoException and restore previous value
					if (e.getCause() instanceof PropertyVetoException) {
						UIManager.getLookAndFeel().provideErrorFeedback(
								getPropertySheet());
						prop.setValue(evt.getOldValue());
					}
				}
			}
		};
		getPropertySheet().addPropertySheetChangeListener(
				propertyChangeListener);
	}

	/**
	 * This method is called from within the constructor to initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is always
	 * regenerated by the Form Editor.
	 */
	// <editor-fold defaultstate="collapsed" desc=" Generated Code
	// ">//GEN-BEGIN:initComponents
	private void initComponents() {
		java.awt.GridBagConstraints gridBagConstraints;

		mainPanel = new javax.swing.JPanel();
		filterPanel = new javax.swing.JPanel();
		jComboBox = new javax.swing.JComboBox();
		resetButton = new javax.swing.JButton();
		defaultButton = new javax.swing.JButton();
		removeButton = new javax.swing.JButton();
		saveButton = new javax.swing.JButton();
		searchButton = new javax.swing.JButton();
		propertySheet = new com.l2fprod.common.propertysheet.PropertySheetPanel();

		setLayout(new java.awt.BorderLayout());

		setFont(new java.awt.Font("Tahoma", 0, 10));
		setOpaque(false);
		//setPreferredSize(new java.awt.Dimension(220, 600));
		mainPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

		mainPanel.setFont(new java.awt.Font("Tahoma", 0, 10));
		//mainPanel.setMaximumSize(new java.awt.Dimension(220, 120));
		filterPanel.setLayout(new java.awt.GridBagLayout());

		//filterPanel.setPreferredSize(new java.awt.Dimension(200, 120));
		jComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] {
				"Item 1", "Item 2", "Item 3", "Item 4" }));
		//jComboBox.setPreferredSize(new java.awt.Dimension(94, 22));
		jComboBox.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				jComboBoxActionPerformed(evt);
			}
		});

		gridBagConstraints = new java.awt.GridBagConstraints();
		gridBagConstraints.gridx = 0;
		gridBagConstraints.gridy = 0;
		gridBagConstraints.gridwidth = 2;
		gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
		gridBagConstraints.ipadx = 20;
		gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
		gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);
		filterPanel.add(jComboBox, gridBagConstraints);

		resetButton.setText(bundle.getString("basepropertyeditor.resetButton"));
		resetButton.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				resetButtonActionPerformed(evt);
			}
		});

		gridBagConstraints = new java.awt.GridBagConstraints();
		gridBagConstraints.gridx = 1;
		gridBagConstraints.gridy = 2;
		gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
		gridBagConstraints.ipadx = 20;
		gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
		gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
		filterPanel.add(resetButton, gridBagConstraints);

		defaultButton.setText(bundle.getString("basepropertyeditor.defaultButton"));
		defaultButton.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				defaultButtonActionPerformed(evt);
			}
		});

		gridBagConstraints = new java.awt.GridBagConstraints();
		gridBagConstraints.gridx = 0;
		gridBagConstraints.gridy = 1;
		gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
		gridBagConstraints.ipadx = 20;
		gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
		gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
		filterPanel.add(defaultButton, gridBagConstraints);

		removeButton.setText(bundle.getString("basepropertyeditor.removeButton"));
		removeButton.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				removeButtonActionPerformed(evt);
			}
		});

		gridBagConstraints = new java.awt.GridBagConstraints();
		gridBagConstraints.gridx = 0;
		gridBagConstraints.gridy = 2;
		gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
		gridBagConstraints.ipadx = 20;
		gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
		gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
		filterPanel.add(removeButton, gridBagConstraints);

		saveButton.setText(bundle.getString("basepropertyeditor.saveButton"));
		saveButton.setEnabled(false);
		saveButton.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				saveButtonActionPerformed(evt);
			}
		});

		gridBagConstraints = new java.awt.GridBagConstraints();
		gridBagConstraints.gridx = 1;
		gridBagConstraints.gridy = 1;
		gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
		gridBagConstraints.ipadx = 20;
		gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
		gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
		filterPanel.add(saveButton, gridBagConstraints);

		searchButton.setText(bundle.getString("basepropertyeditor.searchButton"));
		searchButton.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				searchButtonActionPerformed(evt);
			}
		});

		gridBagConstraints = new java.awt.GridBagConstraints();
		gridBagConstraints.gridx = 0;
		gridBagConstraints.gridy = 3;
		gridBagConstraints.gridwidth = 2;
		gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
		gridBagConstraints.ipadx = 20;
		gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
		filterPanel.add(searchButton, gridBagConstraints);

		mainPanel.add(filterPanel);

		add(mainPanel, java.awt.BorderLayout.NORTH);

		//propertySheet.setPreferredSize(new java.awt.Dimension(200, 600));
		add(propertySheet, java.awt.BorderLayout.CENTER);

	}

	private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {
		if (searchEventListeners.isEmpty())
			throw new RuntimeException("No SearchEventListener set!");
		else {
			getPropertySheet().writeToObject(this.currentObject);
			SearchEvent searchEvent = new SearchEvent(this.currentObject);
			for (Iterator it = searchEventListeners.iterator(); it.hasNext();) {
				((SearchEventListener) it.next()).performAction(searchEvent);
			}
		}
	}

	private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {
		String itemName = getJComboBox().getSelectedItem().toString();
		if (!objectMap.containsKey(itemName)) {
			// maak copy vh object zodat er geen references meer zijn
			NamedObject newObject = (NamedObject) DeepCopy.copy(currentObject);
			newObject.setName(itemName);
			objectMap.put(itemName, newObject);
			getJComboBox().addItem(itemName);

			this.saveButton.setEnabled(false);
			this.resetButton.setEnabled(false);
			this.defaultButton.setEnabled(true);
			this.removeButton.setEnabled(true);
		}

	}

	private void removeButtonActionPerformed(java.awt.event.ActionEvent evt) {
		String itemName = getJComboBox().getSelectedItem().toString();
		if (objectMap.containsKey(itemName)) {
			// als het toevallig de default is de eerste uit de map als default
			// zetten
			// TODO: dit aan de gebruiker melden/vragen
			setDefault(getFirstObjectFromMap());
			currentObject = defaultObject;
			getJComboBox().setSelectedItem(currentObject.getName());
			objectMap.remove(itemName);
			getJComboBox().removeItem(itemName);
		}
	}// GEN-LAST:event_removeButtonActionPerformed

	private void defaultButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_defaultButtonActionPerformed
		String itemName = getJComboBox().getSelectedItem().toString();
		if (objectMap.containsKey(itemName)) {
			setDefault((NamedObject) getMap().get(itemName));
		}
	}// GEN-LAST:event_defaultButtonActionPerformed

	private void resetButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_resetButtonActionPerformed
		System.out.println("reseting to: " + this.currentObject.getName());
		JTextField tf = ((JTextField) getJComboBox().getEditor()
				.getEditorComponent());
		writeToSheet(this.currentObject);
		getJComboBox().setSelectedItem(this.currentObject.getName());
		tf.requestFocusInWindow();
		tf.setText(this.currentObject.getName());
	}// GEN-LAST:event_resetButtonActionPerformed

	private void jComboBoxActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_jComboBoxActionPerformed
		String itemName = getJComboBox().getSelectedItem().toString();
		NamedObject o = getObjectFromMap(itemName);
		if (o != null) {
			currentObject = o;
			getPropertySheet().removePropertySheetChangeListener(
					propertyChangeListener);
			writeToSheet(currentObject);
			getPropertySheet().addPropertySheetChangeListener(
					propertyChangeListener);
		}
	}// GEN-LAST:event_jComboBoxActionPerformed

	protected PropertySheetPanel getPropertySheet() {
		return this.propertySheet;
	}

	private NamedObject getObjectFromMap(String itemName) {
		NamedObject o = null;
		if (objectMap.containsKey(itemName)) {
			o = (NamedObject) DeepCopy.copy(getMap().get(itemName));
		}
		return o;
	}

	private NamedObject getFirstObjectFromMap() {
		return (NamedObject)getMap().values().iterator().next();
	}

	public void addSearchEventListener(
			SearchEventListener newSearchEventListener) {
		searchEventListeners.add(newSearchEventListener);
	}

	public void removeSearchEventListener(
			SearchEventListener newSearchEventListener) {
		searchEventListeners.remove(newSearchEventListener);
	}

	private void editorChanged() {
		// System.err.println("curObj="+this.currentObject+"
		// "+this.currentObject.hashCode());
		// System.err.println("voor read curObj="+this.currentObject+"
		// "+this.currentObject.hashCode());

		this.currentObject = new Filter(bundle.getString("basepropertyeditor.newFilterNameMessage"));
		readFromSheet(this.currentObject);
		jComboBox.setSelectedItem(currentObject.getName());
		
		getJComboBox().requestFocus();
		getJComboBox().getEditor().selectAll();
		this.saveButton.setEnabled(true);
		this.resetButton.setEnabled(true);
		this.defaultButton.setEnabled(false);
		this.removeButton.setEnabled(false);
	}

	protected Map getMap() {
		return objectMap;
	}

	public void setMap(Map newObjectMap) {
		this.objectMap = newObjectMap;
		getJComboBox().setModel(
				new DefaultComboBoxModel(getMap().keySet().toArray()));
		if (getDefault() == null) {
			// als er geen default is de eerste uit de Map pakkken
			setDefault(getFirstObjectFromMap());
		}
		this.currentObject = this.defaultObject;
	}

	abstract void initProperties();

	public void setDefault(NamedObject newObject) {
		this.defaultObject = newObject;
		writeToSheet(defaultObject);
		// TODO in userpreferences opslaan
	}

	protected NamedObject getDefault() {
		return this.defaultObject;
	}

	private javax.swing.JComboBox getJComboBox() {
		return jComboBox;
	}

	private NamedObject readFromSheet(NamedObject objectToWriteTo) {
		getPropertySheet().writeToObject(objectToWriteTo);
		return objectToWriteTo;
	}

	private void writeToSheet(NamedObject newObject) {
		getPropertySheet().removePropertySheetChangeListener(
				propertyChangeListener);
		getPropertySheet().readFromObject(newObject);
		getPropertySheet().addPropertySheetChangeListener(
				propertyChangeListener);
		this.saveButton.setEnabled(false);
		this.resetButton.setEnabled(false);
		this.defaultButton.setEnabled(true);
		this.removeButton.setEnabled(true);

	}

	// Variables declaration - do not modify//GEN-BEGIN:variables
	private javax.swing.JButton defaultButton;

	private javax.swing.JPanel filterPanel;

	private javax.swing.JComboBox jComboBox;

	private javax.swing.JPanel mainPanel;

	private com.l2fprod.common.propertysheet.PropertySheetPanel propertySheet;

	private javax.swing.JButton removeButton;

	private javax.swing.JButton resetButton;

	private javax.swing.JButton saveButton;

	private javax.swing.JButton searchButton;
	// End of variables declaration//GEN-END:variables

}
